/////////////////////////////////////////////////////////////////////////////
// Name of module : pixel_read_ctrl                                        //
// Func           : 控制sdram读模块，读像素素和校正数据                   //
// Author         : heguangzu                                              //
// Simulator      :                                                        //
// Synthesizer    :                                                        //
// version 1.0    : made in Date: 2019.05.23                               //
/////////////////////////////////////////////////////////////////////////////


module pixel_read_ctrl(
    input   wire            I_sclk          ,
    input   wire            I_rst_n         ,
      
    input   wire            I_frame_start   ,   

    input   wire    [10:0]  I_line_max_pixel,//一扫的像素---4的倍数。 从1 开始计数
    input   wire    [5:0]   I_cfg_port_max  ,//最大port_id 从0计数
    input   wire    [5:0]   I_cfg_scan_max  ,//最大scan_id 从0 计数
    input   wire    [1:0]   I_cfg_box_dir   ,//箱体方向
    input   wire    [3:0]   I_cfg_sector_count,//多开数量
    input   wire    [10:0]  I_cfg_sector_width,//分区宽度
    input   wire    [10:0]  I_cfg_sector_height,//区域的高度
    input   wire    [7:0]   I_cfg_port_height,//port的高度
    input   wire    [3:0]   I_cfg_block_max  ,//列模式下多开的数量
    input   wire            I_cfg_pixel_adj_en ,// 逐点调整
    input   wire            I_cfg_pixel_adj_mode,//亮度或色度调整
    input   wire            I_cfg_gap_adj_en   ,// 缝隙调整
    input   wire    [10:0]  I_cfg_win_col_num  ,// 带载列数（宽度）
    input   wire    [10:0]  I_cfg_win_row_num  ,// 带载行数（高度）

    input   wire            I_frame_req        ,
    input   wire    [1:0]   I_frist_frame      ,//第一次SDRAM的切换
    //sdram 操作
    output  wire            O_sdram_req        ,
    output  wire    [20:0]  O_cfg_sdram_addr   ,// 
    output  wire    [9:0]   O_cfg_sdram_len    ,//现在必需是4的倍数
    output  wire    [2:0]   O_cfg_sdram_req_cnt,//读几行 从0开始计数 相当有几折
    output  wire    [20:0]  O_cfg_sdram_add    ,//每行之间的地址差
    output  wire    [20:0]  O_cfg_sdram_col_add,//按列读时，每64相差的地地址
    output  wire    [20:0]  O_cfg_sdram_add1   ,//色度校正中每个分量的地址差
    output  wire    [1:0]   O_cfg_sdram_mode   ,// 0:像素 1：亮度校正 2：色度校正 
    output  wire            O_cfg_sdram_dir    ,// 0：按行读  1：按列读
    input   wire            I_sdram_busy       ,//sdram读模块忙
    output  wire            O_cfg_sdram_data_sel,//读回的数据缓存到那个buf
    
    //
    output  wire            O_gap_coe_req      ,//计算拼缝数据
    output  wire    [9:0]   O_gap_coe_addr_row ,// 行坐标
    output  wire    [9:0]   O_gap_coe_addr_col ,// 列坐标
    output  wire    [9:0]   O_gap_coe_len      ,//现在必需是4的倍数
    output  wire    [2:0]   O_gap_coe_req_cnt  ,//读几行 从0开始计数 相当有几折
    output  wire    [9:0]   O_gap_coe_add      ,//每行之间的地址差
    output  wire            O_gap_coe_dir      ,//按行还是列计算
    input   wire            I_gap_coe_busy     ,//计算拼缝忙
    
    //像素处理
    // input   wire    [1:0]   I_frame_buf_sel    ,//帧切换
    output  wire            O_save_req         ,//保存行读求
    output  wire            O_save_req_data_sel,//那个缓存buf
    output  wire    [5:0]   O_save_port_id   ,
    output  wire    [5:0]   O_save_scan_id    ,
    input   wire            I_save_busy        
    
);

localparam
    LANDSCAPE = 0;

reg  [5:0]  scan_id;
reg  [5:0]  port_id;    
reg         data_end;
reg [1:0]   frist_frame;
reg [1:0]   frist_frame_d;

reg         pixel_clc_req;  //地址计算请求
wire        pixel_clc_end;  //地址计算结束

reg         data_buf_sel;

reg     [20:0]  sdram_addr   ;// 
reg     [9:0]   sdram_len    ;//现在必需是4的倍数
reg     [2:0]   sdram_req_cnt;//读几行 从0开始计数 相当有几折
reg     [20:0]  sdram_add    ;//每行之间的地址差
reg     [20:0]  sdram_col_add;//按列读时，每64相差的地地址
reg     [20:0]  sdram_add1   ;//色度校正中每个分量的地址差

reg     [1:0]   sdram_mode   ;
reg             sdram_dir    ;


wire    [20:0]      pixel_sdram_addr    ;//像素地址
wire    [9:0]       pixel_sdram_len     ;//现在必需是4的倍数
wire    [2:0]       pixel_sdram_req_cnt ;//读几行 从0开始计数 相当有几折
wire    [20:0]      pixel_sdram_add     ;//每行之间的地址差
wire    [20:0]      pixel_sdram_col_add ;//每行之间的地址差

wire    [20:0]      adj_sdram_addr      ;//校正地址
wire    [9:0]       adj_sdram_len       ;//现在必需是4的倍数
wire    [2:0]       adj_sdram_req_cnt   ;//读几行 从0开始计数 相当有几折
wire    [20:0]      adj_sdram_add       ;//每行之间的地址差
wire    [20:0]      adj_sdram_col_add   ;
wire    [20:0]      adj_sdram_add1      ;//每种校正分量的地址差


reg     [9:0]       coe_addr_row    ;
reg     [9:0]       coe_addr_col    ;
reg     [9:0]       coe_len         ;
reg     [2:0]       coe_req_cnt     ;
reg     [9:0]       coe_add         ;

wire    [9:0]       gap_coe_addr_row    ;
wire    [9:0]       gap_coe_addr_col    ;
wire    [9:0]       gap_coe_len         ;
wire    [2:0]       gap_coe_req_cnt     ;
wire    [9:0]       gap_coe_add         ;

reg pixel_adj_en;
reg pixel_adj_mode;
reg gap_adj_en;

reg save_req_r;
reg sdram_data_sel;
reg save_req_data_sel;

reg[7:0] state;

reg[4:0] state_cnt;


localparam [3:0]
    IDLE            = 0,
    IDLE1           = 1,
    START_CLC       = 2,
    END_CLC         = 3,
    WAIT_SDRAM      = 4,
    SDRAM_REQ_R     = 5,
    WAIT_DELAY      = 6,
    WAIT_SDRAM_END  = 7,  
    ADJ_REQ         = 8,
    WAIT_DELAY_1    = 9,
    SAVE_REQ        = 10,
    END_DATA        = 11 ;

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        state <= IDLE;
    else if(I_frame_req  /*    I_frame_start     */)
        state <= IDLE1;
    else
        case(state)
        IDLE1 : state <=  START_CLC;
        
        START_CLC: state <= END_CLC;         //
       
        
        END_CLC: if(pixel_clc_end)  //等待计算结束
                state <= WAIT_SDRAM;         

        WAIT_SDRAM: if(!I_sdram_busy)  //等待sdram读模块空闲，发读请求
                state <= SDRAM_REQ_R;
                
        SDRAM_REQ_R: state <= WAIT_DELAY; 
        
        WAIT_DELAY: if(state_cnt=='d7) // 等待响应
                state <= WAIT_SDRAM_END;
                
        WAIT_SDRAM_END: if(!I_sdram_busy && !I_save_busy)  //sdram 读像素结束,并且没有处理像素
                state <= ADJ_REQ;
                
        ADJ_REQ: if(pixel_adj_en || gap_adj_en) //如果有校正或拼缝
                state <=WAIT_DELAY_1;
             else 
                state <= SAVE_REQ ; 
                
        WAIT_DELAY_1: if(state_cnt=='d7) // 等待响应
                state <= SAVE_REQ;
                
        SAVE_REQ:state <= END_DATA;   //处理开始
                 
        END_DATA: if(data_end)
                    state <= IDLE;
               else 
                    state <= START_CLC;
                
        default: begin
            state <= IDLE;
        end
        endcase
end

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        state_cnt <= 'd0;
    else if(state == WAIT_DELAY || state == WAIT_DELAY_1)
        state_cnt <= state_cnt + 'd1;
    else
        state_cnt <= 'd0;
end

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        scan_id <= 'd0;
    else if(state == IDLE1 || state == IDLE)
        scan_id <= 'd0;
    else if(state == SAVE_REQ)begin
        if(scan_id==I_cfg_scan_max)
            scan_id <= 'd0;
        else
            scan_id <= scan_id+1;
    end
end

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        port_id <= 'd0;
    else if(state == IDLE1)
        port_id <= 'd0;
    else if(state == SAVE_REQ)begin
        if(scan_id==I_cfg_scan_max)
            port_id <= port_id+'d1;
    end
end
always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        data_end <= 'd0;
    else if(state == IDLE || state == IDLE1)
        data_end <= 'd0;
    else if(state == SAVE_REQ && port_id== I_cfg_port_max &&scan_id==I_cfg_scan_max)
        data_end <= 'd1;
end


always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        pixel_clc_req <= 'd0;
    else if(state == START_CLC)
        pixel_clc_req <= 'd1;
    else
        pixel_clc_req <= 'd0;
end


always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        frist_frame <= 'd0;
    else if(state== START_CLC)
        frist_frame <= I_frist_frame;
end


always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        pixel_adj_en <= 'd0;
    else if(state == START_CLC)
        pixel_adj_en <= I_cfg_pixel_adj_en;
end

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        pixel_adj_mode <= 'd0;
    else if(state == START_CLC)
        pixel_adj_mode <= I_cfg_pixel_adj_mode;
end


always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        gap_adj_en <= 'd0;
    else if(state == START_CLC)
        // gap_adj_en <= I_cfg_gap_adj_en;
        gap_adj_en <=  'd0;
end

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        data_buf_sel <= 'd0;
    else if(state == SAVE_REQ)
        data_buf_sel <= data_buf_sel + 1;
end

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        save_req_data_sel <= 'd0;
    else if(state == SAVE_REQ)
        save_req_data_sel <= data_buf_sel ;
end
assign O_save_req_data_sel  =  save_req_data_sel ;

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        sdram_data_sel <= 'd0;
    else if(state == SDRAM_REQ_R)
        sdram_data_sel <= data_buf_sel ;
end
assign O_cfg_sdram_data_sel =  sdram_data_sel ;

always@(posedge I_sclk or negedge I_rst_n)begin
    if(!I_rst_n)
        save_req_r <= 'd0;
    else if(state == SAVE_REQ)
        save_req_r <= 'd1;
    else 
        save_req_r <= 'd0;
end
assign O_save_req = save_req_r;

pixel_addr_decoder   pixel_addr_decoder(
    .I_sclk             (I_sclk ),
    .I_rst_n            (I_rst_n ),
    
    .I_req              (pixel_clc_req),
    .O_req_end          (pixel_clc_end),
    
    .I_port_id          (port_id),
    .I_scan_id          (scan_id),
    .I_frame_sel        (frist_frame),
    
    .I_line_max_pixel   ( I_line_max_pixel      ),//一扫的像素---4的倍数。 从1 开始计数
    .I_cfg_port_max     ( I_cfg_port_max        ),//最大port_id 从0计数
    .I_cfg_scan_max     ( I_cfg_scan_max        ),//最大scan_id 从0 计数
    .I_cfg_box_dir      ( I_cfg_box_dir         ),//箱体方向
    .I_cfg_sector_count ( I_cfg_sector_count    ),//多开数量
    .I_cfg_sector_width ( I_cfg_sector_width    ),//分区宽度
    .I_cfg_sector_height( I_cfg_sector_height   ),//区域的高度
    .I_cfg_port_height  ( I_cfg_port_height     ),//port的高度
    .I_cfg_block_max    ( I_cfg_block_max       ),//列模式下多开的数量
    
    .I_cfg_win_col_num  ( I_cfg_win_col_num     ),// 带载列数（宽度）
    .I_cfg_win_row_num  ( I_cfg_win_row_num     ),// 带载行数（高度）
    
    .O_pixel_sdram_addr         (   pixel_sdram_addr    ),//像素地址
    .O_pixel_sdram_len          (   pixel_sdram_len     ),//现在必需是4的倍数
    .O_pixel_sdram_req_cnt      (   pixel_sdram_req_cnt ),//读几行 从0开始计数 相当有几折
    .O_pixel_sdram_add          (   pixel_sdram_add     ),//每行之间的地址差
    .O_pixel_sdram_col_add      (   pixel_sdram_col_add ),
    
    .O_adj_sdram_addr           (   adj_sdram_addr      ),//校正地址
    .O_adj_sdram_len            (   adj_sdram_len       ),//现在必需是4的倍数
    .O_adj_sdram_req_cnt        (   adj_sdram_req_cnt   ),//读几行 从0开始计数 相当有几折
    .O_adj_sdram_add            (   adj_sdram_add       ),//每行之间的地址差
    .O_adj_sdram_col_add        (   adj_sdram_col_add   ),
    .O_adj_sdram_add1           (   adj_sdram_add1      ),//每种校正分量的地址差

    .O_gap_coe_addr_row         (   gap_coe_addr_row    ),// 行坐标
    .O_gap_coe_addr_col         (   gap_coe_addr_col    ),// 列坐标
    .O_gap_coe_len              (   gap_coe_len         ),//现在必需是4的倍数
    .O_gap_coe_req_cnt          (   gap_coe_req_cnt     ),//读几行 从0开始计数 相当有几折
    .O_gap_coe_add              (   gap_coe_add         )//每行之间的地址差
);


always@(posedge I_sclk )begin
    if(state == SDRAM_REQ_R )begin
        sdram_addr      <= pixel_sdram_addr   ;
        sdram_len       <= pixel_sdram_len    ;
        sdram_req_cnt   <= pixel_sdram_req_cnt;
        sdram_add       <= pixel_sdram_add    ;
        sdram_col_add   <= pixel_sdram_col_add;
        
        sdram_dir       <= I_cfg_box_dir==LANDSCAPE ? 0 : 1;
        sdram_mode      <= 0;
    end 
    else if( state == ADJ_REQ && pixel_adj_en) begin
        sdram_addr      <= adj_sdram_addr   ;
        sdram_len       <= adj_sdram_len    ;
        sdram_req_cnt   <= adj_sdram_req_cnt;
        sdram_add       <= adj_sdram_add    ;
        sdram_add1      <= adj_sdram_add1   ;
        sdram_col_add   <= adj_sdram_col_add;
        
        sdram_dir       <= I_cfg_box_dir==LANDSCAPE ? 0 : 1;
        if(I_cfg_pixel_adj_mode)  //0-色度  1-亮度
            sdram_mode      <= 'd1;  //1-亮度
        else 
            sdram_mode      <= 'd2;  //0-色度
    end
end

assign O_cfg_sdram_addr     = sdram_addr      ;
assign O_cfg_sdram_len      = sdram_len       ;
assign O_cfg_sdram_req_cnt  = sdram_req_cnt   ;
assign O_cfg_sdram_add      = sdram_add       ;
assign O_cfg_sdram_col_add  = sdram_col_add   ;
assign O_cfg_sdram_add1     = sdram_add1      ;
assign O_cfg_sdram_dir      = sdram_dir       ;
assign O_cfg_sdram_mode     = sdram_mode      ;

always@(posedge I_sclk )begin
    if( state == ADJ_REQ) begin
        coe_addr_row<= gap_coe_addr_row;
        coe_addr_col<= gap_coe_addr_col;
        coe_len     <= gap_coe_len     ;
        coe_req_cnt <= gap_coe_req_cnt ;
        coe_add     <= gap_coe_add     ;
    end
end

assign O_gap_coe_addr_row = coe_addr_row ;
assign O_gap_coe_addr_col = coe_addr_col ;
assign O_gap_coe_len      = coe_len      ;
assign O_gap_coe_req_cnt  = coe_req_cnt  ;
assign O_gap_coe_add      = coe_add      ;


reg [5:0]save_port_id;
reg [5:0]save_scan_id;
always@(posedge I_sclk )begin
    if( state == SAVE_REQ ) begin
       save_port_id = port_id;
       save_scan_id = scan_id;
    end
end

assign O_save_port_id = save_port_id;
assign O_save_scan_id = save_scan_id;

reg sdram_req;
assign O_sdram_req = sdram_req;
always@(posedge I_sclk )begin
    if(state == SDRAM_REQ_R) 
       sdram_req <= 'd1;
    else if(state ==ADJ_REQ && pixel_adj_en) //如果有校正
       sdram_req <= 'd1;
    else 
       sdram_req <= 'd0;
end

endmodule
// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker: